package com.ruoyi.business.projectTosView.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.business.projectRecord.domain.ProjectRecord;
import com.ruoyi.business.projectTosView.domain.VProjectTos;
import com.ruoyi.business.projectTosView.domain.params.VProjectTosQueryParams;
import com.ruoyi.business.projectTosView.service.VProjectTosService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.finance.collection.domain.VBillCollection;
import com.ruoyi.finance.collection.domain.vo.ChargeElementsVo;
import com.ruoyi.finance.collection.mapper.ChargeElementMapper;
import com.ruoyi.finance.collection.service.BillCollectionService;
import com.ruoyi.finance.collection.service.ChargeElementService;
import com.ruoyi.finance.collection.service.VBillCollectionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 针对视图【V_PROJECT_TOS】的数据库操作Controller
 *
 * @author 毕京瑞
 * @createTime 2023-07-04 9:14
 */

@RestController
@RequestMapping("/business/projectTos")
public class VProjectTosController extends BaseController {
	
	
	@Autowired
	private VProjectTosService vProjectTosService;
	@Autowired
	private VBillCollectionService vBillCollectionService;
	@Autowired
	private BillCollectionService billCollectionService;
	@Autowired
	private ChargeElementMapper chargeElementMapper;
	
	/**
	 * 根据参数获取【V_PROJECT_TOS】列表
	 *
	 * @param params
	 * @return
	 */
	@GetMapping("/list")
	public TableDataInfo list(VProjectTosQueryParams params) {
		startPage();
		List<VProjectTos> list = vProjectTosService.listByParams(params);
		return getDataTable(list);
	}
	
	
	/**
	 * 根据id获取【V_PROJECT_TOS】详细信息
	 *
	 * @param id
	 * @return
	 */
	@GetMapping(value = "/{id}")
	public AjaxResult getInfo(@PathVariable Long id) {
		return AjaxResult.success(vProjectTosService.getById(id));
	}
	
	
	/**
	 * 新增【V_PROJECT_TOS】
	 */
	@PostMapping
	@Log(title = "V_PROJECT_TOS视图新增项目", businessType = BusinessType.INSERT)
	public AjaxResult add(@Validated @RequestBody VProjectTos vProjectTos) {
		return null;
	}
	
	/**
	 * 修改【V_PROJECT_TOS】
	 */
	@PutMapping
	@Log(title = "V_PROJECT_TOS视图修改项目", businessType = BusinessType.UPDATE)
	public AjaxResult edit(@Validated @RequestBody VProjectTos vProjectTos) {
		return null;
		
	}
	
	/**
	 * 删除【V_PROJECT_TOS】
	 */
	@DeleteMapping("/{ids}")
	@Log(title = "V_PROJECT_TOS视图删除项目", businessType = BusinessType.DELETE)
	public AjaxResult remove(@PathVariable Long[] ids) {
		return null;
	}
	
	
	/**
	 * 一键绑定合同 （固化tosProjectViewList + 绑定合同）
	 *
	 * @param tosProjectViewList
	 * @return
	 */
	@PostMapping("/oneKeyBindContract")
	@Log(title = "V_PROJECT_TOS视图项目绑定合同", businessType = BusinessType.UPDATE)
	public AjaxResult oneKeyBindContract(@Validated @RequestBody List<VProjectTos> tosProjectViewList) {
		//——————————————————————————————绑合同并行处理，捞计费要素一次性处理
		long a = System.currentTimeMillis();
		// 获取传入列表的大小
		int size = tosProjectViewList.size();
		// 用ConcurrentHashMap记录每种PROJECT_TYPE绑定合同成功的数据的PROJECT_ID
		ConcurrentHashMap<String,List<Long>> concurrentHashMap = new ConcurrentHashMap<>();
		// 一开始就初始化好每种PROJECT_TYPE对应的List，避免并行处理时再初始化可能会导致的线程不安全
		// List中元素的初始值设置为-1，便于后续判断该index上的VProjectTos数据是否绑定合同成功，绑定成功则会被set为该VProjectTos的projectId
		concurrentHashMap.put("disc_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		concurrentHashMap.put("bulk_disc_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		concurrentHashMap.put("truck_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		concurrentHashMap.put("cy_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		concurrentHashMap.put("empty_cy_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		concurrentHashMap.put("berth_fee", new ArrayList<Long>(Collections.nCopies(size, -1L)));
		// 使用原子整数来记录成功和失败的计数
		AtomicInteger successCount = new AtomicInteger(0);
		AtomicInteger failCount = new AtomicInteger(0);
		// 重新封装tosProjectViewList，加上索引index
		List<JSONObject> tosProjectViewListOrdered = new ArrayList<>();
		for (int i = 0; i < size; i++) {
			JSONObject tosProjectViewOrdered = new JSONObject();
			tosProjectViewOrdered.put("index",i);
			tosProjectViewOrdered.put("data",tosProjectViewList.get(i));
			tosProjectViewListOrdered.add(tosProjectViewOrdered);
		}
		// 创建线程安全的并发队列，并将传入的列表元素添加到队列中
		ConcurrentLinkedQueue<JSONObject> concurrentTosProjectViewList = new ConcurrentLinkedQueue<>(tosProjectViewListOrdered);
		
		// 创建一个线程池，使用固定大小的线程池，线程数为可用的处理器核心数
		ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
		long b = System.currentTimeMillis();
		// 使用并行流处理并发队列中的元素，进行绑定合同操作
		concurrentTosProjectViewList.parallelStream().forEach(tosProjectViewOrdered -> {
			try {
				// 获取VProjectTos数据
				VProjectTos tosProjectView = JSON.parseObject(tosProjectViewOrdered.getString("data"), VProjectTos.class);
				// 固化tosProjectRecord、绑定合同 (若合同不存在，则不固化)
				ProjectRecord projectRecord = vProjectTosService.saveRecordAndBindContractForTosProjectView(tosProjectView);
				// 若无异常，则成功计数加一
				successCount.incrementAndGet();
				// 为ProjectRecord收款
//				billCollectionService.autoCollection(projectRecord.getProjectId());
				// 如果projectRecord为null，说明该VProjectTos绑定合同失败或者已经成功绑定合同，则不用捞计费要素
				// 如果projectRecord不为null，说明该projectRecord是新绑定的数据，需要捞计费要素出来存到表中
				if (projectRecord!=null){
					int index = tosProjectViewOrdered.getIntValue("index");
					concurrentHashMap.get(projectRecord.getProjectType()).set(index,projectRecord.getProjectId());
				}
			} catch (Exception e) {
				e.printStackTrace();
				// 若出现异常，则失败计数加一
				failCount.incrementAndGet();
			}
		});
		
		// 关闭线程池
		executorService.shutdown();
		long c = System.currentTimeMillis();
		// 对于每种projectType调用存储过程捞出计费要素
		for (String projectType : concurrentHashMap.keySet()){
			// 只保留新绑定成功的数据的projectId
			List<Long> projectIdList = concurrentHashMap.get(projectType).stream().filter(item-> item!=-1L).collect(Collectors.toList());
			// projectIdList不为空，说明该projectType有新数据绑定合同成功，需要捞计费要素
			if (projectIdList.size()!=0){
				// 用存储过程
//				// 求出最大的projectId(即位数最长的projectId)
//				Long longestProjectId = Collections.max(projectIdList);
//				// 求出该projectId的位数，考虑到拼接符','所以还要再+1
//				int digitCount = String.valueOf(longestProjectId).length() + 1;
//				// 求需要分成几个批次处理
//				int batch = 4000/digitCount;
//				for (int i = 0;i < projectIdList.size();i+=batch) {
//					List<Long> subBillCollectionIdS;
//					if (i + batch - 1 < projectIdList.size()) {
//						subBillCollectionIdS = projectIdList.subList(i, i + batch);
//					} else {
//						subBillCollectionIdS = projectIdList.subList(i, projectIdList.size());
//					}
//
//					dealTotalNum += subBillCollectionIdS.size();
					
//					JSONObject jsonObject = new JSONObject();
//					jsonObject.put("flag", 0);
//					jsonObject.put("msg", "");
//					jsonObject.put("projectType", projectType);
//					System.out.println(subBillCollectionIdS.size());
//					// 所有projectId合成一个长字符串传入存储过程，一次性捞完所有的计费要素
//					String projectIds = subBillCollectionIdS.stream().map(String::valueOf).collect(Collectors.joining(","));
//					System.out.println(projectIds);
//					jsonObject.put("projectIds", projectIds);
//					chargeElementMapper.P_INSERT_CHARGE_ELEMENTS(jsonObject);
//					if (jsonObject.getIntValue("flag") == 0) {
//						System.out.println("没执行成功");
//					}
//				}
				
				// 直接用后端SQL查询和插入计费要素
				List<ChargeElementsVo> chargeElementsVoList = chargeElementMapper.selectChargeElementsFromTable(projectIdList,projectType);
				chargeElementMapper.insertChargeElementsBatch(chargeElementsVoList);
			}
		}

		long d = System.currentTimeMillis();
		System.out.println("绑定合同耗时：" + (c-b) + "ms");
		System.out.println("查询和插入计费要素总耗时：" + (d-c) + "ms");
		System.out.println("处理总耗时：" + (d-a) + "ms");
		// 返回处理结果
		return AjaxResult.success("一键绑定合同成功！成功" + successCount.get() + "/" + size + "条，未找到合同" + failCount.get() + "/" + size + "条");
	}
	
	/**
	 * 解绑合同 （根据conID删除projectTyp数据项 ）
	 *
	 * @param tosProjectViewList
	 * @return
	 */
	@PostMapping("/unBindContract")
	@Log(title = "V_PROJECT_TOS视图项目解绑合同", businessType = BusinessType.UPDATE)
	public AjaxResult unBindContract(@Validated @RequestBody List<VProjectTos> tosProjectViewList) {
		// 记录成功数、失败数
		int size = tosProjectViewList.size();
		int successCount = 0;
		int failCount = 0;
		
		// 遍历tosProjectViewList
		for (VProjectTos tosProjectView : tosProjectViewList) {
			try {
				// 如果已经计费了，提示先删除计费再解绑合同
				List<String> projectIds = new ArrayList<>();
				projectIds.add(String.valueOf(tosProjectView.getProjectId()));
				List<VBillCollection> vBillCollectionList = vBillCollectionService.listVBillCollectionByProjectIds(projectIds);
				if (vBillCollectionList.size() > 0) {
					return AjaxResult.error(tosProjectView.getProjectId() + "项目已计费，请先删除计费再解绑合同");
				}
				// 固化tosProjectRecord、绑定合同 (若合同不存在，则不固化)
				vProjectTosService.unBindContract(tosProjectView);
				// 若无异常，则successCount++
				successCount++;
			} catch (Exception e) {
				// 若出现异常，则failCount++
				failCount++;
			}
		}
		// 返回成功 成功X/X条，失败X/X条
		return AjaxResult.success("解绑合同成功！成功" + successCount + "/" + size + "条，未找到合同" + failCount + "/" + size + "条");
	}
}
